package com.eastfair.pay.chinaums.CScanB;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;

/**
 * @author kkqiao
 * c扫b更新二维码接口
 * 说明：
 * 对于需要批量生成二维码，在使用时再绑定账单信息；或者因为某种原因需要更换二维码中账单信息
 * 的场景下，可以使用二维码更新接口来更新二维码。
 * 其中walletOption字段只针对一次性码，上送值包括“SINGLE”与“MULTIPLE”，对固定码和固定金额
 * 码无效；对于“SINGLE”两个app同时扫码弹出密码框后，不同app或相同app的不同用户，只有先扫
 * 码的可以支付。
 *  测试地址：http://58.247.0.18:29015/v1/netpay/bills/update-qrcode
 *  生产地址：https://api-mop.chinaums.com/v1/netpay/bills/update-qrcode
 */
public class UpdateQrCode {

    static String appid = "10037e6f6823b20801682b6a5e5a0006";
    static String appkey = "1c4e3b16066244ae9b236a09e5b312e8";
    static String url = "https://test-api-open.chinaums.com/v1/netpay/bills/update-qrcode";

    public static void main(String[] args) throws Exception{
        //1. 组建请求报文
        UpdateQrCodeBody reqBody = new UpdateQrCodeBody();
        reqBody.requestTimestamp = "2019-07-31 11:00:55";
        reqBody.mid = "898460107420248";
        reqBody.tid = "00000001";
        reqBody.instMid = "QRPAYDEFAULT";
        reqBody.qrCodeId = "10002765033224017146368158";
        System.out.println("request body:\n"+reqBody);

        //2. 获取认证报文，timestamp为当前日期，老旧日期无法请求成功
        String authorization = getAuthorization(appid,appkey,"20190731110000","nonce",reqBody.toString());
        System.out.println("authorization:\n"+authorization);

        //3. 发送http请求，并解析返回信息
        String response = request(url,authorization,reqBody.toString());
        System.out.println("response:\n"+response);
    }

    /**
     * 发送http请求
     * @param url 请求url
     * @param authorization 认证报文
     * @param reqBody  请求体
     * @return response
     */
    static String request(String url, String authorization, String reqBody){
        String response = "";
        PrintWriter out = null;
        BufferedReader in = null;
        try{
            URL realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();
            HttpURLConnection httpUrlConnection = (HttpURLConnection) conn;
            httpUrlConnection.setRequestProperty("Content-Type", "application/json");
            httpUrlConnection.setRequestProperty("authorization",authorization);
            httpUrlConnection.setDoOutput(true);
            httpUrlConnection.setDoInput(true);
            out = new PrintWriter(httpUrlConnection.getOutputStream());
            out.write(reqBody);
            out.flush();
            httpUrlConnection.connect();
            in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                response += line;
            }
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            try {
                if (out != null) { out.close();}
                if (in != null) {in.close();}
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return response;
    }

    /**
     * 获取签名头
     * @param appid
     * @param appkey
     * @param timestamp 格式:"yyyyMMddHHmmss"
     * @param nonce 随机字符串，
     * @param body 请求体
     * @return authorization 认证报文
     * @throws Exception
     */
    static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception {
        byte[] data = body.getBytes("utf-8");
        InputStream is = new ByteArrayInputStream(data);
        String testSH = DigestUtils.sha256Hex(is);
        String s1 = appid+timestamp+nonce+testSH;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256"));
        byte[] localSignature = mac.doFinal(s1.getBytes("utf-8"));
        String localSignatureStr = Base64.encodeBase64String(localSignature);
        return  "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\"";
    }

    static class UpdateQrCodeBody{
        //消息ID
        String msgId;
        //报文请求时间，格式yyyy-MM-ddHH:mm:ss
        String requestTimestamp;
        //请求系统预留字段
        String srcReserve;
        //商户号
        String mid;
        //终端号
        String tid;
        //业务类型
        String instMid;
        //账单号
        String billNo;
        //账单日期
        String billDate;
        //账单状态
        String billStatus;
        //账单描述
        String billDesc;
        //支付总金额
        int totalAmount;
        //商品信息
        List<GoodsItem> goods;
        //会员号
        String memberId;
        //桌号、柜台号、房间号
        String counterNo;
        //账单过期时间
        String expireTime;
        //支付结果通知地址
        String notifyUrl;
        //网页跳转地址
        String returnUrl;
        //二维码ID
        String qrCodeId;
        //系统ID
        String systemId;
        //担保交易标识
        String secureTransaction;
        //钱包选项
        String walletOption;
        //实名认证姓名
        String name;
        //实名认证手机号
        String mobile;
        //实名认证证件类型
        String certType;
        //实名认证证件号
        String certNo;
        //是否需要实名认证
        String fixBuyer;

        String toJson(){
            StringBuilder sb = new StringBuilder();
            sb.append("{");
            if (this.msgId != null) sb.append("\"msgId\":\"" + this.msgId + "\",");
            if (this.requestTimestamp != null) sb.append("\"requestTimestamp\":\"" + this.requestTimestamp + "\",");
            if (this.srcReserve != null) sb.append("\"srcReserve\":\"" + this.srcReserve + "\",");
            if (this.mid != null) sb.append("\"mid\":\"" + this.mid + "\",");
            if (this.tid != null) sb.append("\"tid\":\"" + this.tid + "\",");
            if (this.instMid != null) sb.append("\"instMid\":\"" + this.instMid + "\",");
            if (this.billNo != null) sb.append("\"billNo\":\"" + this.billNo + "\",");
            if (this.billDate != null) sb.append("\"billDate\":\"" + this.billDate + "\",");
            if (this.billStatus != null) sb.append("\"billStatus\":\"" + this.billStatus + "\",");
            if (this.billDesc != null) sb.append("\"billDesc\":\"" + this.billDesc + "\",");
            if (this.totalAmount != 0) sb.append("\"totalAmount\":\"" + this.totalAmount + "\",");
            if (this.goods != null && this.goods.size()>0) {
                sb.append("\"goods\":[");
                for(int i=0;i<goods.size();i++){
                    sb.append(goods.get(i));
                    sb.append(",");
                }
                if (sb.charAt(sb.length() - 1) == ',')
                    sb.deleteCharAt(sb.length() - 1);
                sb.append("],");
            }
            if (this.memberId != null) sb.append("\"memberId\":\"" + this.memberId + "\",");
            if (this.counterNo != null) sb.append("\"counterNo\":\"" + this.counterNo + "\",");
            if (this.expireTime != null) sb.append("\"expireTime\":\"" + this.expireTime + "\",");
            if (this.notifyUrl != null) sb.append("\"notifyUrl\":\"" + this.notifyUrl + "\",");
            if (this.returnUrl != null) sb.append("\"returnUrl\":\"" + this.returnUrl + "\",");
            if (this.qrCodeId != null) sb.append("\"qrCodeId\":\"" + this.qrCodeId + "\",");
            if (this.systemId != null) sb.append("\"systemId\":\"" + this.systemId + "\",");
            if (this.secureTransaction != null) sb.append("\"secureTransaction\":\"" + this.secureTransaction + "\",");
            if (this.walletOption != null) sb.append("\"walletOption\":\"" + this.walletOption + "\",");
            if (this.name != null) sb.append("\"name\":\"" + this.name + "\",");
            if (this.mobile != null) sb.append("\"mobile\":\"" + this.mobile + "\",");
            if (this.certType != null) sb.append("\"certType\":\"" + this.certType + "\",");
            if (this.certNo != null) sb.append("\"certNo\":\"" + this.certNo + "\",");
            if (this.fixBuyer != null) sb.append("\"fixBuyer\":\"" + this.fixBuyer + "\",");

            if (sb.charAt(sb.length() - 1) == ',')
                sb.deleteCharAt(sb.length() - 1);
            sb.append("}");
            return sb.toString();
        }

        public String toString(){
            return this.toJson();
        }
        static class GoodsItem {
            //商品ID
            String goodsId;
            //商品名称
            String goodsName;
            //商品数量
            String quantity;
            //商品单价（分）
            String price;
            //商品分类
            String goodsCategory;
            //商品说明
            String body;

            String toJson(){
                StringBuilder sb = new StringBuilder();
                sb.append("{");
                if(this.goodsId!=null) sb.append("\"goodsId\":\""+this.goodsId+"\",");
                if(this.goodsName!=null) sb.append("\"goodsName\":\""+this.goodsName+"\",");
                if(this.quantity!=null) sb.append("\"quantity\":\""+this.quantity+"\",");
                if(this.price!=null) sb.append("\"price\":\""+this.price+"\",");
                if(this.goodsCategory!=null) sb.append("\"goodsCategory\":\""+this.goodsCategory+"\",");
                if(this.body!=null) sb.append("\"body\":\""+this.body+"\",");
                if(sb.charAt(sb.length()-1) == ',')
                    sb.deleteCharAt(sb.length()-1);
                sb.append("}");
                return sb.toString();
            }
            public String toString(){
                return this.toJson();
            }
        }

    }

}
